
#ifndef __KEY_H
#define __KEY_H

#include <apr_date.h>
#include "../crypt/AbstractKey.h"
#include "SQLiteTransactor.h"

#include "../crypt/EncryptionKey.h"
#include "../crypt/DecryptionKey.h"
#include "../crypt/SigningKey.h"
#include "../crypt/CheckingKey.h"

class KeyDB;

/** A lazy-evaluating key class in conjunction with the keys
 * database. */
class Key
{
   public:
      /** The type of IDs of different key purpose types. */
      enum keypurposetype  {   KEYPURPOSE_ENCRYPTION              = (1 << 0),
                               KEYPURPOSE_DECRYPTION              = (1 << 1),
                               KEYPURPOSE_SIGNING                 = (1 << 2),
                               KEYPURPOSE_CHECKING                = (1 << 3)  };

      /** The type of IDs of different errors when opening key from
       * the database. */
      enum keyopenerror    {   KEY_OPEN_ERROR__NO_ERROR           = 0,
                               KEY_OPEN_ERROR__INVALID_KEY_NAME   = 1,
                               KEY_OPEN_ERROR__INVALID_KEY_DST    = 2,
                               KEY_OPEN_ERROR__KEY_NOT_FOUND      = 3,
                               KEY_OPEN_ERROR__FAILED_SANITY      = 4,
                               KEY_OPEN_ERROR__KEY_IMPORT_FAILED  = 5,
                               KEY_OPEN_ERROR__KEY_NULL           = 6  };

      Key(KeyDB *ikdb, const char *iname, keypurposetype ithistype);
      virtual ~Key();

      void initFromAbstractKey(KeyDB *ikdb, const AbstractKey &tkey, const char *pwd, keypurposetype ithistype);
      Key(KeyDB *ikdb, const EncryptionKey &tkey, const char *pwd);
      Key(KeyDB *ikdb, const DecryptionKey &tkey, const char *pwd);
      Key(KeyDB *ikdb, const SigningKey &tkey, const char *pwd);
      Key(KeyDB *ikdb, const CheckingKey &tkey, const char *pwd);
      const char *getName();
      const keypurposetype getPurposeType();
      const char *getPurposeTypeName();

      SETGET_MACRO_AS_STRING_DECL(Key, KeyType, sqlite_key, "keytype")
      SETGET_MACRO_AS_STRING_DECL(Key, KeyData, sqlite_key, "keydata")
      SETGET_MACRO_AS_STRING_DECL(Key, KeyMark, sqlite_key, "keymark")
      SETGET_MACRO_AS_STRING_DECL(Key, Owner, sqlite_key, "owner")
      ADDRMV_MACRO_AS_CHARFLAGS_DECL(Key, KeyMark, sqlite_key, "keymark")
      INCDEC_MACRO_AS_INT64_DECL(Key, UseReferenceCount, sqlite_key, "usedrefcount")
      INCDEC_MACRO_AS_INT64_DECL(Key, ExistenceReferenceCount, sqlite_key, "existsrefcount")
      SETGET_MACRO_AS_APRDATE_DECL(Key, DateCreated, sqlite_key, "rfc822date")
      SETGET_MACRO_AS_STRING_DECL(Key, DateCreated, sqlite_key, "rfc822date")

      void precache();
      bool commit();
      bool update();

      static void showKeyOpenError(const char *kname, keypurposetype tpur, keyopenerror terr);
      AbstractKey *getKey(const char *pwd);
      AbstractKey *getKey(const char *pwd, keyopenerror *errpntr);
      static EncryptionKey *getEncryptionKey(KeyDB *ikdb, const char *pwd, const char *iname);
      static DecryptionKey *getDecryptionKey(KeyDB *ikdb, const char *pwd, const char *iname);
      static SigningKey *getSigningKey(KeyDB *ikdb, const char *pwd, const char *iname);
      static CheckingKey *getCheckingKey(KeyDB *ikdb, const char *pwd, const char *iname);
      static AbstractKey *tryToGetKeyFromText(const char *keytype, const char *keypwd, const char *keytext, const char *keyname, keyopenerror *errpntr);
      static const char *keypurposetypename[];
   private:
      /** The key database for reading/writing changes to the key to/from. */
      KeyDB *kdb;
      /** The transactor for caching changes. */
      SQLiteTransactor *sqlite_key;
      /** The key purpose type of the key represented by this class. */
      keypurposetype thistype;
      
      void initNull();
      void init();
};

#endif
